﻿using Helpers.Enums;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Filters;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace Helpers.Factories
{
    public static class CacheKeyFactory
    {
        public static ApiCacheOptions ApiCacheOptions => DiHelper.GetRequiredService<ApiCacheOptions>();
        /// <summary>
        /// 对特殊的value进行格式化
        /// </summary>
        public static Dictionary<string, Func<string, string>> ValueFormatter { get; set; } = new Dictionary<string, Func<string, string>>()
        {
            {"url",x=>new Uri(x).Host }
        };

        /// <summary>
        /// 根据字符串生成md5
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static string Build(string s)
        {
            return SecurityHelper.ToMD5(s);
        }

        public static string Build(HttpRequest httpRequest, CacheKeyBuildFromEnum from, params string[] keyNames)
        {
            HashSet<string> nameUsed = new HashSet<string>();
            keyNames = keyNames.OrderBy(x => x).ToArray();
            List<string> values = new List<string>();
            //Query
            if (from.HasFlag(CacheKeyBuildFromEnum.Query) || from == CacheKeyBuildFromEnum.All)
            {
                values.AddRange(keyNames.Select(x =>
                {
                    if (!nameUsed.Contains(x) && httpRequest.Query.TryGetValue(x, out var value) && !string.IsNullOrWhiteSpace(value))
                    {
                        nameUsed.Add(x);
                        return ValueFormat(x, value.ToString());
                    }
                    return null;
                }));
            }
            //Headers
            if (from.HasFlag(CacheKeyBuildFromEnum.Header) || from == CacheKeyBuildFromEnum.All)
            {
                values.AddRange(keyNames.Select(x =>
                {
                    if (!nameUsed.Contains(x) && httpRequest.Headers.TryGetValue(x, out var value) && !string.IsNullOrWhiteSpace(value))
                    {
                        nameUsed.Add(x);
                        return ValueFormat(x, value.ToString());
                    }
                    return null;
                }));
            }

            var ret = string.Join("-", values.Where(x => !string.IsNullOrWhiteSpace(x)));
            return System.Web.HttpUtility.UrlEncode(ret);
        }

        public static string GetCacheKey(HttpRequest httpRequest, CacheKeyBuildFromEnum from, params string[] keyNames)
        {
            var path = httpRequest.Path.Value.TrimEnd('/') + "/";
            return GetCacheKey(path, httpRequest, from, keyNames);
        }

        public static string GetCacheKey(string cachePath, HttpRequest httpRequest, CacheKeyBuildFromEnum from, params string[] keyNames)
        {
            var path = cachePath.TrimEnd('/') + "/";
            var key = keyNames.Length == 0 ? Build(httpRequest.QueryString.ToString()) : Build(httpRequest, from, keyNames);
            return string.IsNullOrWhiteSpace(key) ? null : $"{ApiCacheOptions.PreFullPath}{path}{key}{ApiCacheOptions.SufFullPath}";
        }

        private static string ValueFormat(string key, string value)
        {
            if (ValueFormatter.Keys.Any(x => Regex.IsMatch(key, x, RegexOptions.IgnoreCase)))
            {
                var formatter = ValueFormatter.First(x => Regex.IsMatch(key, x.Key, RegexOptions.IgnoreCase)).Value;
                return formatter(value);
            }
            return value;
        }
    }
}
